#!/usr/bin/perl

# ---------- Init variables -------
#my $version = "0.0001";
# ---------- external readable parameters -------
## Functions
##-------------------------------------------------------
#
# stict syntax checking.
use strict;
use CGI qw(param);
use SNMP_util;
use SIM_cgi;
use SIM_base;
use SIM_settings;
use SIM_nodeInfo;

#BEGIN { $Exporter::Verbose=1 }

# Startupscript translater
my $tool = $ARGV[0];
my $vendor = $ARGV[1];
my $action = $ARGV[2];
my $option1 = $ARGV[3];
my $option2 = $ARGV[4];

my $httpScriptName = $ENV{'SCRIPT_NAME'};

# SNMP settings to prevent error logging.
$SNMP_Session::suppress_warnings = 1000;

sub listAps {
  my $option1 = $_[0];
  my $option2 = $_[1];
  chdir "$SIMparam{'SIMdeviceDir'}/$vendor";
  my $tableHeader = "<TR BGCOLOR=#DDDDDD ALIGN=center>
                        <TD>Num</TD>
                        <TD>Name</TD>
                        <TD>ip addr</TD>
                        <TD>mac addr</TD>
                        <TD>model</TD>
                        <TD>organisation</TD>
                        <TD>location</TD>
                        <TD>floor</TD>
                        <TD>snmpLoc</TD>
                        <TD>controller</TD>
                        <TD>status</TD>
                        <TD>Uptime</TD></TR>";
  print("<CENTER><H3>Accesspoint info</H3><TABLE>$tableHeader");
  my @devices = ();
  if ( $option1 eq "device" ) {
    push(@devices, $option2);
  } else {
    @devices = <*>;
  }
  my $num = 0;
  foreach my $entry (@devices) {
    if ( -f "$entry/isAP" ) {
      $num++;
      # read info
      my $ipAddr = catFileLine("$entry/ipaddr");
      my $modelType = catFileLine("$entry/modelType");
      my $organisation = catFileLine("$entry/organisation");
      my $building = catFileLine("$entry/building");
      my $floor = catFileLine("$entry/floor");
      my $snmpLoc = catFileLine("$entry/snmpLoc");
      # secondary info
      my $ipDir = getIpDir($ipAddr);
      my $macAddr = catFileLine("$ipDir/snmpmac.txt");
      my $nodeColor = &testNodeStatus($ipAddr);
      # snmp info
      my $controllerIp = catFileLine("$entry/controllerIp");
      my $controllerName = dispHostName($controllerIp, "data");
      my $community = catFileLine("$entry/community");
      my $snmpString = $community . "@" . $controllerIp . ":::::" . "1";
      my $macoid = catFileLine("$entry/macOid");
#     my $upTime = "skipped, down";
#     my $status = "";
      my $statusColor = "";
      my $upTime = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.5.2.1.4.1.12.$macoid");
      my $status = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.5.2.1.4.1.19.$macoid");
      # only test snmp if the node is up.
      if ( $status eq "1" ) {
        $status = "oke"; 
        if ( $nodeColor eq "#00FF33" ) {
          $statusColor = "#00FF33";
        } else {
          $statusColor = "#008888";
        }
      } else {
        $statusColor = "#006699";
      }
#     my $upTime = "$upTime, $controllerIp $community $macoid";
      printDebug(1, "listAps snmpString = $snmpString, controllerIp = $controllerIp.");

      print("<TR BGCOLOR=#FFFFCC>
               <TD ALIGN=right> $num </TD>
               <TD> <A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$entry>$entry</A> </TD>
               <TD BGCOLOR=$nodeColor><A HREF=$httpScriptName?mon+nodestatus+$ipAddr>$ipAddr</A> </TD>
               <TD> $macAddr </TD>
               <TD ALIGN=center> $modelType </TD>
               <TD> $organisation </TD>
               <TD> $building </TD>
               <TD> $floor </TD>
               <TD> $snmpLoc </TD>
               <TD> <A HREF=$httpScriptName?mon+nodestatus+$controllerIp>$controllerName</A> </TD>
               <TD BGCOLOR=$statusColor ALIGN=center> $status </TD>
               <TD ALIGN=right>$upTime</TD>
            ");
    }
  }
  print("$tableHeader</TABLE>");
}

sub splitArubaClientInfo {
  # this sub will split the oid into an formatted mac and an ip part.
  my $oid = $_[0];
  my ( $mac, $ipAddr, $return );
  my @info = split('\.', $oid);
  my $num = 0;
  foreach my $entry (@info) {
    my $hexPart = sprintf("%02x", $entry);
#   print("$num=$hexPart ");
    if ( $num eq 0 ) {
      $mac = $hexPart;
    } elsif ( $num < 6 ) {
      $mac = "$mac:$hexPart";
    } elsif ( $num eq 6 ) {
      $ipAddr = $entry;
    } else {
      $ipAddr = "$ipAddr.$entry";
    }
    $num++;
  }
  return("$mac", "$ipAddr");
}

sub mac2oid {
  my $mac = $_[0];
  my $oid;
  my @macArr = split(':', $mac);
  foreach my $part (@macArr) {
    my $dec = hex($part);
    $oid = "$oid.$dec";
  }
  my $return = substr($oid, 1);
# print("oid=$oid, return=$return. ");
  return $return;
}

sub getPhyApType {
  my $apPhyType = $_[0];
  if ( $apPhyType eq "1" ) {
    $apPhyType = "dot11a";
  } elsif ( $apPhyType eq "2" ) {
    $apPhyType = "dot11b";
  } elsif ( $apPhyType eq "3" ) {
    $apPhyType = "dot11g";
  }
  return $apPhyType;
}

sub listRogueAps {
  my $option1 = $_[0];
  my $option2 = $_[1];
  my $vendorDir = "$SIMparam{'SIMdeviceDir'}/$vendor";
  chdir $vendorDir;
  my @devices = <*>;
  my $header = "<TR BGCOLOR=#EEEEEE><TD>ourName</TD><TD>Chan</TD><TD>neighbour</TD><TD>bssid</TD><TD>radio</TD><TD>Chan</TD><TD>ssid</TD><TD>s2n</TD><TD>status</TD><TD>Class</TD></TR>";
  print("<CENTER><H3>Other Ap's</H2>");
  my $lastName;
  my @sortApList = ();
  # build index list (sorting the ap's on device name.
  foreach my $entry (@devices) {
    if ( -f "$entry/isController" ) {
      my $ipAddr = catFileLine("$entry/ipaddr");
      my $community = catFileLine("$entry/community");
      my $snmpString = $community . "@" . $ipAddr . ":::::" . "1";
      my @apList = &snmpwalk("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.4");
# we need to sort this info on device name.
      foreach my $entry (@apList) {
        my ( $index , $ssid ) = split(':', $entry);
        my @part = split('\.', $index);
        my $ourMac = &oidToMac("$part[0].$part[1].$part[2].$part[3].$part[4].$part[5]");
        my $ourDevName = catFileLine("$SIMparam{'SIMmacDatab'}/$ourMac/arubaApName");
        push(@sortApList, "$ourDevName $snmpString $index $ssid");
      }
    }
  }
  # start displaying the info
  print("<TABLE>");
  foreach my $entry (sort(@sortApList)) {
    my ( $ourDevName, $snmpString, $index , $ssid ) = split(' ', $entry);
    my @part = split('\.', $index);
    my $theirMac = &oidToMac("$part[7].$part[8].$part[9].$part[10].$part[11].$part[12]");
    my $theirDevName = catFileLine("$SIMparam{'SIMmacDatab'}/$theirMac/arubaApName");
    if ((( $option1 ne "device" ) or ( $option2 eq $ourDevName )) and ( $ourDevName ne $theirDevName )) {
      # only get the detailed info if needed.
#     my $macOid = "$part[0].$part[1].$part[2].$part[3].$part[4].$part[5]";
      my $ourMac = &oidToMac("$part[0].$part[1].$part[2].$part[3].$part[4].$part[5]");
      my $radioType = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.1.$index");
      my $signalStrengt = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.5.$index");
      my $monAPInfoCurrentChannel = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.2.$index");
      my $monAPInfoClassification = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.3.$index");
      my $monAPInfoStatus = &snmpget("$snmpString", "1.3.6.1.4.1.14823.2.2.1.6.7.1.1.1.10.$index");
      $radioType = &getPhyApType($radioType);
      my $ourChannel = catFileLine("$vendorDir/$ourDevName/channel-$radioType");
      if ( $lastName ne $ourDevName ) {
        print($header);
        $lastName = $ourDevName;
      }
      my $lineColor = "#FFFFCC";
      if ( $monAPInfoClassification ne "1" ) {
        $lineColor = "#CCFFFF";
      }
      my $channelColor = $lineColor;
      if ( $ourChannel eq $monAPInfoCurrentChannel ) {
        $channelColor = "#FFFF44";
      }
      print("<TR BGCOLOR=$lineColor>
               <TD> <A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$ourDevName>$ourDevName</A> </TD>
               <TD ALIGN=right BGCOLOR=$channelColor>$ourChannel</TD>
               <TD> <A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$theirDevName>$theirDevName</A> </TD>
               <TD>$theirMac</TD>
               <TD>$radioType</TD>
               <TD ALIGN=right BGCOLOR=$channelColor>$monAPInfoCurrentChannel</TD>
               <TD>$ssid</TD>
               <TD ALIGN=right>$signalStrengt</TD>
               <TD>$monAPInfoStatus</TD>
               <TD>$monAPInfoClassification</TD>
             </TR>");
    }
  }
  print("$header</TABLE>");
}

sub listClients {
  my $option1 = $_[0];
  my $option2 = $_[1];
  my $vendorDir = "$SIMparam{'SIMdeviceDir'}/$vendor";
  chdir $vendorDir;
  my @devices = <*>;
  my %clientList = ();
  my %snmpInfo = ();
  foreach my $entry (@devices) {
    if ( -f "$entry/isController" ) {
      my $ipAddr = catFileLine("$entry/ipaddr");
      my $community = catFileLine("$entry/community");
      my $snmpString = $community . "@" . $ipAddr . ":::::" . "1";
      my @devClientList = &snmpwalk("$snmpString", "1.3.6.1.4.1.14823.2.2.1.4.1.2.1.11");
      foreach my $entry (@devClientList) {
        my ( $index , $bssidInfo ) = split(':', $entry);
        my $bssid = &make_hex_string($bssidInfo);
        my $apName = catFileLine("$SIMparam{'SIMmacDatab'}/$bssid/arubaApName");
        if (( $option1 ne "device" ) or ( $option2 eq $apName )) {
#         print("option1=$option1, option2=$option2, apName=$apName, bssid=$bssid.<BR>");
          $clientList{$index} = "$apName $bssid";
          $snmpInfo{$index} = $snmpString;
        }
      }
    }
  }
  print("<CENTER><H3>Client list</FONT></H3><TABLE>");
  my $lastAp;
  my $header = "<TR BGCOLOR=#EEEEEE><TD></TD><TD>ip addr</TD><TD>mac address</TD><TD>mac vendor</TD><TD>login</TD><TD>role</TD><TD>apName</TD><TD>essid</TD><TD>bssid</TD><TD>radio</TD><TD>vlan</TD><TD>s2n</TD><TD>TxMbps</TD><TD>RxMbps</TD><TD>TxBytes</TD><TD>RxBytes</TD><TD COLSPAN=2>authenticator</TD></TR>";
  my $numClients = 0;
  my $authenticated = 0;
  my %speeds = ( "1", "1", "2", "2", "3", "5.5", "4", "6", "5", "9", "6", "11", "7", "12",
                  "8", "18", "9", "24", "10", "36", "11", "48", "12", "54");
  foreach my $clientIndex (sort {$clientList{$a} cmp $clientList{$b}} keys %clientList) {
    $numClients++;
    my ( $macAddr, $ipAddr ) = splitArubaClientInfo($clientIndex);
    my $macVendor = displayOui($macAddr);
    my ( $apName, $bssid ) = split(' ', $clientList{$clientIndex});
    my $macOid = mac2oid($macAddr);
    my $bssidOid = mac2oid($bssid);
    # snmp stuff
    my $snmpString = $snmpInfo{$clientIndex};
    my $userName = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.4.1.2.1.3.$clientIndex");
    my $userRole = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.4.1.2.1.4.$clientIndex");
    my $authServer = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.4.1.2.1.8.$clientIndex");
    my $sig2noise = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.1.2.2.1.7.$macOid.$bssidOid");
    my $staTransmitRate = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.1.2.2.1.8.$macOid.$bssidOid");
    my $staReceiveRate = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.1.2.2.1.9.$macOid.$bssidOid");
    my $staTxBytes = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.1.2.3.1.2.$macOid.$bssidOid");
    $staTxBytes = &dotFormatted($staTxBytes);
    my $staRxBytes = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.1.2.3.1.4.$macOid.$bssidOid");
    $staRxBytes = &dotFormatted($staRxBytes);
    if ( $authServer ne "" ) {
      $authenticated++;
    }
    my $authSrvName = dispHostName($authServer, "data");
    my $vlan = &snmpget($snmpString, ".1.3.6.1.4.1.14823.2.2.1.4.1.2.1.22.$clientIndex");
    my $radioType = catFileLine("$vendorDir/$apName/apPhyType-$bssid");
    my $nodeColor = &testNodeStatus($ipAddr);
    my $essid = catFileLine("$SIMparam{'SIMmacDatab'}/$bssid/essidName");
    if ( $lastAp ne $apName ) {
      print("$header");
    }
    print("<TR BGCOLOR=#FFFFCC>
             <TD ALIGN=right> $numClients </TD>
             <TD BGCOLOR=$nodeColor> <A HREF=$httpScriptName?mon+nodestatus+$ipAddr>$ipAddr</A> </TD>
             <TD> $macAddr </TD>
             <TD> $macVendor </TD>
             <TD> $userName </TD>
             <TD> $userRole </TD>
             <TD> <A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$apName>$apName</A> </TD>
             <TD> $essid </TD>
             <TD> $bssid </TD>
             <TD> $radioType </TD>
             <TD> $vlan </TD>
             <TD ALIGN=right> $sig2noise </TD>
             <TD ALIGN=right> $speeds{$staTransmitRate} </TD>
             <TD ALIGN=right> $speeds{$staReceiveRate} </TD>
             <TD ALIGN=right> $staTxBytes </TD>
             <TD ALIGN=right> $staRxBytes </TD>
             <TD> $authServer </TD>
             <TD> $authSrvName </TD>
           </TR>");
     $lastAp = $apName;
  }
  print("$header</TABLE>Authenticated clients: $authenticated.");

}


sub listRadios {
  my $option1 = $_[0];
  my $option2 = $_[1];

  my $vendorDir = "$SIMparam{'SIMdeviceDir'}/$vendor";
  if ( -d $vendorDir ) {
    chdir $vendorDir;
    my @devices = ();
    if ( $option1 eq "device" ) {
      push(@devices, $option2);
    } else {
      @devices = <*>;
    }

    my $header = "<TR BGCOLOR=#EEEEEE><TD>num</TD><TD>name</TD><TD>ipAddr</TD><TD>bssid</TD><TD>essid</TD><TD>radio</TD><TD>channel</TD><TD>kbps</TD><TD>clients</TD><TD>noise</TD><TD>sig2noise</TD><TD>retryR</TD><TD>lowspeedR</TD><TD>nonUnicast</TD><TD>fragRate</TD><TD>Receive error</TD></TR>";
    print("<CENTER><H3>Radio list</H3><TABLE>");
    my $num = 0;
    foreach my $entry (@devices) {
#     print("$entry ");
      if ( -f "$entry/isAP" ) {
        $num++;
        my $dispNum = $num;
        my $dispHeader = $header;
        my @radioMacList = <$entry/radioMac-*>;
        foreach my $radioMac (@radioMacList) {
          my ( $dummy, $macAddr ) = split('radioMac-', $radioMac);
          my $ipAddr = catFileLine("$entry/ipaddr");
          my $nodeColor = &testNodeStatus($ipAddr);
          my $essid = catFileLine("$entry/essid-$macAddr");
          my $apPhyType = catFileLine("$entry/apPhyType-$macAddr");
          # snmp stuff
          my $controllerIp = catFileLine("$entry/controllerIp");
          my $community = catFileLine("$entry/community");
          my $snmpString = $community . "@" . $controllerIp . ":::::" . "1";
          my $index = catFileLine("$radioMac");
          my $numClientsOid = catFileLine("$SIMparam{'SIMmacDatab'}/$macAddr/wlsxWlanAPBssidEntry");
          my $numClients = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.5.2.1.7.1.12.$numClientsOid");
          my $noise = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.3.1.13.$index");
          my $channel = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.3.1.8.$index");
          my $signal2noise = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.3.1.14.$index");
          my $bwRate = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.12.$index");
          my $retryRate = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.13.$index");
          my $lowSpeedR = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.14.$index");
          my $nonUnicastR = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.15.$index");
          my $fragRate = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.16.$index");
          my $receiveErrorR = &snmpget("$snmpString", ".1.3.6.1.4.1.14823.2.2.1.1.3.5.1.17.$index");
          my $noiseColor;
          if ( $noise < 60 ) {
            $noiseColor = "#FF3300";
          } elsif ( $noise < 70 ) {
            $noiseColor = "#FF9900";
          } elsif ( $noise < 80 ) {
            $noiseColor = "#FFFF00";
          }
          print("$dispHeader<TR BGCOLOR=#FFFFCC>
                  <TD ALIGN=right> $dispNum </TD>
                  <TD> <A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$entry>$entry</A> </TD>
                  <TD BGCOLOR=$nodeColor> $ipAddr </TD>
                  <TD> $macAddr </TD>
                  <TD> $essid </TD>
                  <TD> $apPhyType </TD>
                  <TD ALIGN=right> $channel </TD>
                  <TD ALIGN=right> $bwRate </TD>
                  <TD ALIGN=right> $numClients </TD>
                  <TD ALIGN=right BGCOLOR=$noiseColor> $noise </TD>
                  <TD ALIGN=right> $signal2noise </TD>
                  <TD ALIGN=right> $retryRate </TD>
                  <TD ALIGN=right> $lowSpeedR </TD>
                  <TD ALIGN=right> $nonUnicastR </TD>
                  <TD ALIGN=right> $fragRate </TD>
                  <TD ALIGN=right> $receiveErrorR </TD>
                </TR>");
          $dispNum = "";
          $dispHeader = "";
        }
      }
    }
    print("$header</TABLE>");
  } else {
    print("Oops, $vendorDir not found");
  }
}

sub listAll {
  my $vendorDir = "$SIMparam{'SIMdeviceDir'}/$vendor";
  my @controlerList = ();
  my @apList = ();
  if ( -d $vendorDir ) {
    print("<CENTER><TABLE>");
    chdir $vendorDir;
    my @devices = <*>;
    foreach my $entry (@devices) {
      if ( -f "$entry/isAP" ) {
        push(@apList, $entry);
      } elsif ( -f "$entry/isController") {
        push(@controlerList, $entry);
      }
    }
    print("<TR><TD>Controllers:</TD>");
    my $num = 0;
    foreach my $entry (@controlerList){
      my $ipAddr = catFileLine("$entry/ipaddr");
      my $nodeColor = &testNodeStatus($ipAddr);
      print("<TD BGCOLOR=$nodeColor><A HREF=$httpScriptName?mon+nodestatus+$ipAddr>$entry</A></TD>");
      $num++;
      if ( $num eq 10 ) {
        print("</TR><TR><TD></TD>");
        $num = 0;
      }
    }
    print("</TR><TR><TD>Access points:</TD> ");
    my $num = 0;
    foreach my $entry (@apList){
      my $ipAddr = catFileLine("$entry/ipaddr");
      my $nodeColor = &testNodeStatus($ipAddr);
      print("<TD BGCOLOR=$nodeColor><A HREF=$httpScriptName?$tool+$vendor+searchInfo+device+$entry>$entry</A></TD>");
      $num++;
      if ( $num eq 10 ) {
        print("</TR><TR><TD></TD>");
        $num = 0;
      }
    }
    print("</TABLE>");
  } else {
    print("Oops, $vendorDir not found.");
  }
}


sub printMenu {
  print("<TABLE WIDTH=100% BORDER=0 CELLSPACING=0><TR><TD BGCOLOR=#EEEEEE><CENTER>");
  printEntry2("Overview", "Overview page", "$tool+$vendor+$action", "vendor+$vendor+none", "", "line", "", "");
  printEntry2("AP List", "Accesspoint info", "$tool+$vendor+$action", "vendor+$vendor+apInfo", "", "line", "|", "");
  printEntry2("Radio List", "Radio info", "$tool+$vendor+$action", "vendor+$vendor+radioInfo", "", "line", "|", "");
  printEntry2("Client List", "Client info", "$tool+$vendor+$action", "vendor+$vendor+clientInfo", "", "line", "|", "");
  printEntry2("Neighbour List", "Interfering AP info", "$tool+$vendor+$action", "vendor+$vendor+rogueInfo", "", "line", "|", "");
  print("</TD></TR></TABLE>");

# print(" tool=$tool, vendor=$vendor, action=$action, option1=$option1, option2=$option2.<HR>");
}

#--------------------------- Main ---------------------------
# most scripts will be hostname based, because devices can change dynamically from controller.

&printMenu;

if ( $action eq "apInfo" ) {
  &listAps;
} elsif ( $action eq "radioInfo" ) {
  &listRadios;
} elsif ( $action eq "clientInfo" ) {
  &listClients;
} elsif ( $action eq "rogueInfo" ) {
  &listRogueAps;
} elsif ( $action eq "searchInfo" ) {
  print("<CENTER><H2>Searching info for $option1 = $option2</H2>");
  &listAps($option1, $option2);
  &listRadios($option1, $option2);
  &listClients($option1, $option2);
  &listRogueAps($option1, $option2);;
} else {
  &listAll;
}
